#ifndef __OACTION_INTERVAL_H__
#define __OACTION_INTERVAL_H__

#include "model/oEase.h"

/** @brief Scales a CCNode object to a zoom factor by modifying it's position,
 scale, rotate and opacity attributes.
 @warning This action doesn't support "reverse"
 */
class oDLL oAnimateTo: public CCActionInterval
{
public:
	enum
	{
		None = 0,
		Pos = 1,
		Scale = 1<<1,
		Rotate = 1<<2,
		Opacity = 1<<3
	};
	oAnimateTo();
	void setEase(uint32 type, oEaseFunc func);
	/** Initializes the action with position, scale, rotate and opacity */
	bool initWithDuration(ccTime duration, float posX, float posY, float scaleX, float scaleY, float rotate, GLubyte opacity);
	virtual CCObject* copyWithZone(CCZone* pZone);
	virtual void startWithTarget(CCNode *pTarget);
	virtual void update(ccTime time);
public:
	/** Creates the action with position, scale, rotate and opacity. */
	static oAnimateTo* actionWithDuration(ccTime duration, float posX, float posY, float scaleX, float scaleY, float rotate, GLubyte opacity);
protected:
	float m_fStartPosX;
	float m_fStartPosY;
	float m_fEndPosX;
	float m_fEndPosY;
	float m_fDeltaPosX;
	float m_fDeltaPosY;

	float m_fStartScaleX;
  	float m_fStartScaleY;
    float m_fEndScaleX;
	float m_fEndScaleY;
	float m_fDeltaScaleX;
	float m_fDeltaScaleY;

	float m_fStartRotate;
	float m_fEndRotate;
	float m_fDeltaRotate;

	GLubyte m_nStartOpacity;
	GLubyte m_nEndOpacity;
	short m_nDeltaOpacity;

	uint32 m_flag;

	uint32 m_easeFlag;
	oEaseFunc m_easePos;
	oEaseFunc m_easeScale;
	oEaseFunc m_easeRotate;
	oEaseFunc m_easeOpacity;
};

/** 
@brief An interval action is an action that takes place within a certain period of time.
It has an start time, and a finish time. The finish time is the parameter
duration plus the start time.

These CCActionInterval actions have some interesting properties, like:
- They can run normally (default)
- They can run reversed with the reverse method
- They can run with the time altered with the Accelerate, AccelDeccel and Speed actions.

For example, you can simulate a Ping Pong effect running the action normally and
then running it again in Reverse mode.

Example:

CCAction *pingPongAction = CCSequence::actions(action, action->reverse(), nullptr);
*/
class oDLL oActionInterval : public CCFiniteTimeAction
{
public:
	/** how many seconds had elapsed since the actions started to run. */
	inline ccTime getElapsed(void) { return m_elapsed; }

	PROPERTY_NAME(ccTime, Time);
	PROPERTY(float, m_speed, Speed);

	/** initializes the action */
	bool initWithDuration(ccTime d);

	void pause();
	bool isPaused() const;
	void resume();

	/** returns true if the action has finished */
	virtual bool isDone(void);

	virtual CCObject* copyWithZone(CCZone* pZone);
	virtual void step(ccTime dt);
	virtual void startWithTarget(CCNode *pTarget);
	/** returns a reversed action */
	virtual oActionInterval* reverse(void);

public:
	oActionInterval();
	/** creates the action */
	static oActionInterval* actionWithDuration(ccTime d);

public:
	//extension in CCGridAction 
	void setAmplitudeRate(CGFloat amp);
	CGFloat getAmplitudeRate(void);

protected:
	ccTime m_elapsed;
	bool m_pause;
};

/** @brief Runs actions sequentially, one after another, with speed can be set.
 */
class oDLL oSequence : public oActionInterval
{
public:
	~oSequence(void);
    bool initOneTwo(CCFiniteTimeAction *pActionOne, CCFiniteTimeAction *pActionTwo);
	virtual CCObject* copyWithZone(CCZone* pZone);
	virtual void startWithTarget(CCNode *pTarget);
	virtual void stop();
	virtual void update(ccTime time);
	virtual oActionInterval* reverse();
	CCFiniteTimeAction* one();
	CCFiniteTimeAction* two();
public:
	static oSequence* actions(CCFiniteTimeAction *pAction1, ...);
	static oSequence* actionsWithArray(CCArray *actions);
	static oSequence* actionOneTwo(CCFiniteTimeAction *pActionOne, CCFiniteTimeAction *pActionTwo);
protected:
	CCFiniteTimeAction* m_pActions[2];
	ccTime m_split;
	int m_last;
};

class oFrameActionDef;

class oDLL oFrame : public oActionInterval
{
public:
	virtual ~oFrame();
	virtual void update( ccTime time );
	virtual void startWithTarget( CCNode *pTarget );
	virtual CCObject* copyWithZone(CCZone* pZone);
	void setLoop(bool loop);
	virtual oActionInterval* reverse();
	static oFrame* actionWithDef(oFrameActionDef* def);
private:
	bool _loop;
	int _lastFrameIndex;
	float _interval;
	oFrameActionDef* _def;
};

#endif
